package com.nulldev.util.java.scripting.brainfuck;

import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;

import javax.script.AbstractScriptEngine;
import javax.script.Bindings;
import javax.script.ScriptContext;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptException;
import javax.script.SimpleBindings;

public class BrainfuckEngine extends AbstractScriptEngine {
	private List<Bindings> bindings = new ArrayList<Bindings>();

    @Override
    public Object eval(String script, ScriptContext context) throws ScriptException {
        Bindings bindings = context.getBindings(ScriptContext.ENGINE_SCOPE);
        if(bindings == null) bindings = new SimpleBindings();
        for(Bindings b : this.bindings) {
            bindings.putAll(b);
        }
        final BrainfuckInterpreter interpreter = new BrainfuckInterpreter(bindings.containsKey("cycles") ? (int)bindings.get("cycles") : 10000, bindings.containsKey("memory") ? (int)bindings.get("memory") : 1<<15);
        try {
            return interpreter.process(script.toCharArray(), bindings.containsKey("input") ? (String)bindings.get("input") : "");
        } catch(BrainfuckInterpreter.BrainfuckException e) {
            throw new ScriptException(e);
        }
    }

    @Override
    public Object eval(Reader reader, ScriptContext context) throws ScriptException {
        StringBuilder sb = new StringBuilder();
        try {
            int i;
            while((i = reader.read()) != -1) {
                sb.append((char)i);
            }
        } catch(IOException e) {
            throw new ScriptException(e);
        }
        return eval(sb.toString(), context);
    }

    @Override
    public Bindings createBindings() {
        final Bindings b = new SimpleBindings();
        this.bindings.add(b);
        return b;
    }

    @Override
    public ScriptEngineFactory getFactory() {
        return BrainfuckFactory.INSTANCE;
    }
}
